package com.hqd.ch03.v26.tx.transaction.interceptor;

import com.hqd.ch03.v26.aopalliance.intercept.MethodInterceptor;
import com.hqd.ch03.v26.aopalliance.intercept.MethodInvocation;
import com.hqd.ch03.v26.jdbc.datasource.ConnectionHolder;
import com.hqd.ch03.v26.tx.transaction.support.TransactionSynchronizationManager;
import com.hqd.ch03.v26.utils.DataSourceUtils;
import lombok.Data;

import javax.sql.DataSource;
import java.sql.Connection;

@Data
public class TransactionInterceptor implements MethodInterceptor {
    private DataSource dataSource;
    private TransactionAttributeSource transactionAttributeSource;

    public TransactionInterceptor() {

    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object resource = TransactionSynchronizationManager.getResource(dataSource);
        if (resource == null) {
            resource = new ConnectionHolder(dataSource.getConnection());
            TransactionSynchronizationManager.bindResource(dataSource, resource);
        }
        ConnectionHolder ch = (ConnectionHolder) resource;
        TransactionAttribute txAttr = this.transactionAttributeSource == null ? null : transactionAttributeSource.
                getTransactionAttribute(invocation.getMethod(), invocation.getMethod().getDeclaringClass());
        Connection connection = ch.getConnection();
        DataSourceUtils.prepareConnectionForTransaction(connection, txAttr);
        connection.setAutoCommit(false);
        try {
            Object retVal = invocation.proceed();
            if (txAttr != null) {
                connection.commit();
            }
            return retVal;
        } catch (Throwable e) {
            if (txAttr != null) {
                connection.rollback();
            }
            //      completeTransactionAfterThrowing(transactionStatus, e);
            throw e;
        } finally {
            connection.close();
            TransactionSynchronizationManager.unbindResource(dataSource);
        }
        // commitTransactionAfterReturning(transactionStatus);
    }
}
